一般刪除的話資料就永遠消失了,有時候我們為了避免某些重要資料不小心刪除後再也無法救回的情況,會讓資料變成軟刪除模式。
軟刪除指的是在進行刪除後不是將資料清除,而是給資料打上"已刪除"的標籤,這樣在之後查詢資料時自動避開這些被打上已刪除標籤的資料。
Laravel 也有提供簡便設定資料軟刪除的方法,接著就來實作。
首先要幫資料表加上軟刪除標籤的欄位,建立一個更新 users 資料表的 migration。
sail artisan make:migration update_user_add_soft_delete --table users
Migration 的 up / down 內容
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->softDeletes(); //加入 deleted_at 欄位
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropSoftDeletes();
});
}
$table->softDeletes() 會新增一個日期格式的 deleted_at 欄位,作為 Model 進行刪除跟查詢時的依據。
別忘了建好後要跑 migration
sail artisan migrate
再來要在 Model 中加上對應軟刪除的特性
/app/Models/User.php
@@ -7,10 +7,12 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
+use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
+ use SoftDeletes;
/**
* The attributes that are mass assignable.
這樣就設定好模型了
接著新增一條刪除 User 用的路由
/routes/web.php
@@ -62,3 +62,7 @@ Route::post('/confirm-password', [ConfirmablePasswordController::class, 'store']
Route::post('/logout', [AuthenticatedSessionController::class, 'destroy'])
->middleware('auth')
->name('logout');
+
+Route::post('/delete-account', [RegisteredUserController::class, 'destroy'])
+ ->middleware('auth')
+ ->name('account.delete');
路由指向 RegisteredUserController 的 destroy 方法,這東西還不存在所以也要新增。
/app/Http/Controllers/Auth/RegisteredUserController.php
@@ -52,4 +52,9 @@ class RegisteredUserController extends Controller
+ public function destroy(Request $request)
+ {
+ }
接下來要怎麼找出該刪哪個 user 呢? 傳送 id 然後用 find 找出來刪掉是一個方法,不過 Laravel 提供了更方便的方法。
因為我們給路由加上了 middleware('auth') ,代表這是個需要經過身分驗證才能請求的路由,而經過這類路由的請求都可以用 Laravel 的 Auth 取得發送請求的 User 資訊。
一般來說也只有用戶本人可以刪除自己,所以直接找出發送請求的用戶並將他的資料刪除。
/app/Http/Controllers/Auth/RegisteredUserController.php
@@ -55,6 +55,8 @@ class RegisteredUserController extends Controller
public function destroy(Request $request)
- {
+ {
+ $user = Auth::user(); // 取得用戶資料
+ $user->delete(); // 刪除用戶
}
刪除 user 之後就是跟登出一樣的步驟,消除 session 然後導向首頁。
@@ -57,6 +57,14 @@ class RegisteredUserController extends Controller
public function destroy(Request $request)
{
$user = Auth::user();
$user->delete();
+
+ Auth::guard('web')->logout();
+
+ $request->session()->invalidate();
+
+ $request->session()->regenerateToken();
+
+ return redirect('/');
}
接著來建立前端的請求。
把刪除帳號的選項做在右上角的下拉選單中
/resources/js/Layouts/Authenticated.js
@@ -62,6 +62,12 @@ export default function Authenticated({ auth, header, children }) {
as='button'>
Log Out
</Dropdown.Link>
+ <Dropdown.Link
+ href={route("account.delete")}
+ method='post'
+ as='button'>
+ Delete Account
+ </Dropdown.Link>
</Dropdown.Content>
</Dropdown>
</div>
直接向剛剛建立的 account.delete 路由發送請求,不用帶任何參數。
畫面更新好後就可以勇敢點下去啦,步驟都正確的話就會被導向 Laravel 的首頁,然後沒辦法再用同一個帳號登入。
可以到資料庫中看看,剛剛被刪除的帳號,他的 deleted_at 會被押上時間,這樣一般進行搜尋的時候就會被忽略掉。
如果要把被軟刪除的資料復原的話,用 restore()
$user->restore();
可以在搜尋資料的時候指定要包含被刪除的資料
User::withTrashed()->restore(); // 復原所有被軟刪除的資料
或是只找出被刪除的資料
$deletedUsers = User::onlyTrashed()->get();
不想軟刪除而是完全刪除的話也有方法
$user->forceDelete(); // 硬刪除一筆資料
User::onlyTrashed()->forceDelete(); // 硬刪除所有被軟刪除的資料
不想用 deleted_at 作為欄位名稱的話,可以在 Model 中宣告自訂的 DELETED_AT 名稱。
@@ -13,6 +13,8 @@ class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
use SoftDeletes;
+
+ const DELETED_AT = 'deletedAt';
migration 裡也要改名稱
$table->softDeletes('deletedAt');